﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using DemoApp.CustService;
using Microsoft.Phone.Controls;

namespace DemoApp.ViewModels
{
    public class CustomersViewModel : ViewModelBase
    {
        private CustomersServiceClient _client;
        private List<Customer> _customers;
        private RelayCommand _deleteCustomerCommand;
        private RelayCommand _editCustomerCommand;
        private RelayCommand _newCustomerCommand;
        private RelayCommand _saveCustomerCommand;
        private RelayCommand _cancelCommand;

        private static Customer _selectedCustomer;
        private static Customer _inputCustomer;

        private static Action _selectedMethod;

        private string _mainPageUri = "/MainPage.xaml";
        private string _newEditDialogPageUri = "/Views/NewEditDialog.xaml";

        public CustomersViewModel()
        {
            if (DesignerProperties.IsInDesignTool) return;

            createClient();

            _client.GetCustomersCompleted += customersGetCustomersCompleted;
            _client.InsertCustomerCompleted += ClientInsertCustomerCompleted;
            _client.RemoveCustomerCompleted += ClientRemoveCustomerCompleted;
            _client.UpdateCustomerCompleted += ClientUpdateCustomerCompleted;

            loadCustomersList();
        }

        #region Properties

        public List<Customer> Customers
        {
            get { return _customers; }
            set
            {
                if (_customers == value) return;
                _customers = value;

                OnPropertyChanged("Customers");
            }
        }

        public Customer SelectedCustomer
        {
            get { return _selectedCustomer; }
            set
            {
                if (_selectedCustomer == value) return;
                _selectedCustomer = value;

                OnPropertyChanged("SelectedCustomer");

                EditCustomerCommand.RaiseCanExecuteChanged();
                DeleteCustomerCommand.RaiseCanExecuteChanged();
            }
        }

        public Customer InputCustomer
        {
            get { return _inputCustomer; }
            set
            {
                if (_inputCustomer == value) return;
                _inputCustomer = value;

                OnPropertyChanged("InputCustomer");
            }
        }

        #region CommandProperties
        public RelayCommand CancelCommand
        {
            get { return _cancelCommand ?? (_cancelCommand = new RelayCommand(() =>
                                                                                  {
                                                                                      navigateToPage(_mainPageUri);

                                                                                      SelectedCustomer = null;
                                                                                  })); }
        }

        public RelayCommand SaveCustomerCommand
        {
            get
            {
                return _saveCustomerCommand ?? (_saveCustomerCommand = new RelayCommand(delegate
                                                                                            {
                                                                                                _selectedMethod
                                                                                                    ();

                                                                                                navigateToPage(
                                                                                                    _mainPageUri);

                                                                                                SelectedCustomer = null;
                                                                                            }));
            }
        }

        public RelayCommand NewCustomerCommand
        {
            get
            {
                return _newCustomerCommand ??
                       (_newCustomerCommand = new RelayCommand(
                                                  delegate
                                                      {
                                                          _selectedMethod =
                                                              insertCustomer;

                                                          InputCustomer = new Customer();

                                                          navigateToPage(_newEditDialogPageUri);
                                                      }));
            }
        }

        public RelayCommand EditCustomerCommand
        {
            get
            {
                return _editCustomerCommand ??
                       (_editCustomerCommand =
                        new RelayCommand(delegate
                                             {
                                                 _selectedMethod = updateCustomer;

                                                 InputCustomer = new Customer()
                                                                     {
                                                                         CustomerId = SelectedCustomer.CustomerId,
                                                                         FirstName = SelectedCustomer.FirstName,
                                                                         LastName = SelectedCustomer.LastName,
                                                                         PhoneNumber = SelectedCustomer.PhoneNumber
                                                                     };

                                                 navigateToPage(_newEditDialogPageUri);
                                             },
                                         canUpdateCustomer));
            }
        }

        public RelayCommand DeleteCustomerCommand
        {
            get
            {
                return _deleteCustomerCommand ??
                       (_deleteCustomerCommand = new RelayCommand(
                                                     onDeleteCommand,
                                                     canDeleteCustomer));
            }
        }
        #endregion

        #endregion

        private void onDeleteCommand()
        {
            var result = MessageBox.Show("Do you want delete this customer?",
                                         ((PhoneApplicationFrame)Application.Current.RootVisual).Name,
                                         MessageBoxButton.OKCancel);

            if (result == MessageBoxResult.OK)
            {
                deleteCustomer();
            }
        }

        private void navigateToPage(string uri)
        {
            var p = (Application.Current.RootVisual as PhoneApplicationFrame);

            if (p != null)
            {
                p.Navigate(new Uri(uri, UriKind.Relative));
            }
        }

        #region CRUD operations

        private bool canUpdateCustomer()
        {
            return SelectedCustomer != null;
        }

        private bool canDeleteCustomer()
        {
            return SelectedCustomer != null;
        }

        private void showOperationResult(AsyncCompletedEventArgs e)
        {
            if (e.Cancelled || e.Error != null)
                MessageBox.Show("Service error!",
                    ((PhoneApplicationFrame)Application.Current.RootVisual).Name,
                    MessageBoxButton.OK );

            else loadCustomersList();
        }

        private void createClient()
        {
            if (_client == null) _client = new CustomersServiceClient();
        }

        private void updateCustomer()
        {
            _client.UpdateCustomerAsync(InputCustomer);
        }

        private void ClientUpdateCustomerCompleted(object sender, AsyncCompletedEventArgs e)
        {
            showOperationResult(e);
        }

        private void deleteCustomer()
        {
            _client.RemoveCustomerAsync(SelectedCustomer);
        }

        private void ClientRemoveCustomerCompleted(object sender, AsyncCompletedEventArgs e)
        {
            showOperationResult(e);
        }

        private void insertCustomer()
        {
            var customer = new Customer
                               {
                                   CustomerId = Guid.NewGuid(),
                                   FirstName = InputCustomer.FirstName,
                                   LastName = InputCustomer.LastName,
                                   PhoneNumber = InputCustomer.PhoneNumber
                               };

            _client.InsertCustomerAsync(customer);
        }

        private void ClientInsertCustomerCompleted(object sender, AsyncCompletedEventArgs e)
        {
            showOperationResult(e);
        }

        private void loadCustomersList()
        {
            _client.GetCustomersAsync();
        }

        private void customersGetCustomersCompleted(object sender, GetCustomersCompletedEventArgs e)
        {
            Customers = e.Result.ToList();
        }

        #endregion
    }
}